package com.smartEdu.module.thrift.common;

import org.apache.thrift.server.AbstractNonblockingServer.AbstractNonblockingServerArgs;
import org.apache.thrift.server.TServer.AbstractServerArgs;
import org.apache.thrift.server.TThreadedSelectorServer;
import org.apache.thrift.server.TThreadedSelectorServer.Args;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TTransportException;
import com.smartEdu.commons.ClassStatic;
import com.smartEdu.commons.LogCvt;
import com.smartEdu.exception.SystemInitException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import org.apache.thrift.TMultiplexedProcessor;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TCompactProtocol;

public class ThriftServer {
	
	private int port;
	private String clsname;
	private TThreadedSelectorServer tServer;
	private TMultiplexedProcessor processor;
	
	private void start() {
		try {
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					LogCvt.info("Thrift Server starting");
					tServer.serve();
					LogCvt.info("Thrift Server shutdown success");
				}
			}).start();
			
		} catch (Exception e) {
			throw new SystemInitException("Thrift Server 启动失败", e);
		}
	}

	public ThriftServer(int port, int clstype) {
		this.port = port;
		Class<?> cls = AbstractServerArgs.class;
		switch (clstype) {
		case 1:
			clsname = TServerEnum.TSimpleServer.getName();
			cls = AbstractServerArgs.class;
			break;
		case 2:
			clsname = TServerEnum.TThreadPoolServer.getName();
			cls = org.apache.thrift.server.TThreadPoolServer.Args.class;
			break;
		case 3:
			clsname = TServerEnum.TNonblockingServer.getName();
			cls = AbstractNonblockingServerArgs.class;
			break;
		case 4:
			clsname = TServerEnum.THsHaServer.getName();
			cls = org.apache.thrift.server.THsHaServer.Args.class;
			break;
		case 5:
			clsname = TServerEnum.TThreadedSelectorServer.getName();
			cls = org.apache.thrift.server.TThreadedSelectorServer.Args.class;
			break;
		default:
			break;
		}
		reflectTServer(cls);
	}
	
	/**
	 * 通过反射获取相应的TServer实例
	 * 并调用有参构造函数
	 */
	private void reflectTServer(Class<?> arg) throws SystemInitException{
		try {
			Class<?> cls = Class.forName(clsname);
			Constructor<?> c = cls.getConstructor(arg);
//			AbstractServerArgs<?> args = initArgs();
			tServer = (TThreadedSelectorServer) c.newInstance(initArgs());
		} catch (InstantiationException | IllegalAccessException 
				| NoSuchMethodException | SecurityException 
				| IllegalArgumentException | InvocationTargetException
				| TTransportException | ClassNotFoundException e) {
			LogCvt.error("Thrift Server Error",e);
			throw new SystemInitException("Thrift Server 初始化失败", e);
		}
	}
	
	/**
	 * 初始化TServer
	 */
	private Args initArgs() throws TTransportException {
		processor = new TMultiplexedProcessor();
		TNonblockingServerSocket socket = new TNonblockingServerSocket(port);
        return new Args(socket).processor(processor)
        		.transportFactory(new TFramedTransport.Factory())
        		.protocolFactory(new TCompactProtocol.Factory());
	}
	
	/**
	 * 注册TProcessor信息,对接口对应单服务
	 * 在start前必须先执行该方法，否则报错
	 */
	private void registerTProcessor(ThriftProcessor tfp) 
					throws NoSuchMethodException, SecurityException,
					  InstantiationException, IllegalAccessException, 
					  IllegalArgumentException, InvocationTargetException {
		Constructor<?> c = tfp.getClsProcessor().getConstructor(
				tfp.getClsIface());
		//此处注入具体Iface的实现类实例
		TProcessor tProcessor = (TProcessor) c.newInstance(tfp.getIfaceImpl());
		processor.registerProcessor(tfp.getProcessorName(), tProcessor);
	}
	
	public void stop() {
		tServer.stop();
	}
	
	/**
	 * 根据传入的包名初始化所有带有@ThriftServiceIface注解的
	 * thrift接口服务实现类
	 */
	public void initProcessor(String packpath) throws Exception {
		try {
//			WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
			Map<String, Object> map = ClassStatic.appContext.getBeansWithAnnotation(ThriftServiceIface.class);
			for (Map.Entry<String, Object> entry : map.entrySet()) {
				Class<?> cls = entry.getValue().getClass();
				String name = cls.getPackage().getName();
				if (name.equals(packpath)) {
					Class<?>[] interfacesClazs = cls.getInterfaces();
					for (Class<?> claz : interfacesClazs) {
//						String clsname = claz.getCanonicalName();
						String clsname = claz.getName();
						int idx = clsname.lastIndexOf("$") + 1;
						clsname = clsname.substring(0, idx) + "Processor";
						Class<?> c = Class.forName(clsname);
						ThriftProcessor processor = new ThriftProcessor();
						processor.setProcessorName(entry.getKey());
						processor.setClsProcessor(c);
						processor.setClsIface(claz);
						processor.setIfaceImpl(entry.getValue());
						registerTProcessor(processor);
					}
				}
			}
		} catch (ClassNotFoundException | NoSuchMethodException 
				| SecurityException | InstantiationException 
				| IllegalAccessException | IllegalArgumentException 
				| InvocationTargetException e) {
			LogCvt.error("thrift初始化processor失败",e);
			throw new Exception(e);
		}
		start();
	}
}
